package com.xishu.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.xishu.bo.RequestParam;
import com.xishu.config.Constant;
import com.xishu.dao.DaoUtil;
import com.xishu.entity.User;
import com.xishu.entity.customer.Customer;
import com.xishu.service.CommonService;
import com.xishu.service.CustomerService;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.ThreadContext;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

import static com.xishu.config.Constant.THREAD_LOCAL_VARIABLE_STRIPE_TERMINAL_PAY;
import static com.xishu.config.Constant.THREAD_LOCAL_VARIABLE_USER_ID;

public class ServletUtil {
    private static Logger logger = LoggerFactory.getLogger(ServletUtil.class);

    /**
     * 获取当前用户
     *
     * @return
     */
    public static User getUser() throws Exception {
        Long userId = getUserId();

        if (userId == null) {
            return null;
        }

        User user = new User();
        user.setId(userId);
        User findTheUser = CommonService.getInstance().findEntity(user, true);

        return findTheUser;
    }

    /**
     * 查找用户
     *
     * @param userId
     * @return
     */
    public static User findUser(Long userId) {
        return DaoUtil.getInstance().findById(userId, User.class);
    }

    /**
     * 设置用户信息
     *
     * @param user
     */
    public static void setUser(User user) {
        setSessionAttribute(Constant.SESSION_USER, user);
    }

    /**
     * 将会员信息写到缓存
     *
     * @param customer
     */
    public static void setCustomer(Customer customer) {
        setSessionAttribute(Constant.SESSION_CUSTOMER, customer.getId());
    }

    /**
     * 清空会员信息
     */
    public static void cleanCustomer() {
        cleanSessionAttribute(Constant.SESSION_CUSTOMER);
    }

    /**
     * 获取会员的ID
     *
     * @return
     */
    public static Long getCustomerId() {
        Long customerId = getSessionAttribute(Constant.SESSION_CUSTOMER);

        return customerId;
    }

    /**
     * 获取会员信息
     *
     * @return
     */
    public static Customer getCustomer() throws Exception {
        Long customerId = getSessionAttribute(Constant.SESSION_CUSTOMER);

        if (customerId == null) {
            return null;
        }

        Optional<Customer> customerOptional = CustomerService.getInstance().findCustomerOptional(customerId);
        if (customerOptional.isPresent()) {
            return customerOptional.get();
        }

        return null;
    }

    /**
     * 获取用户的ID
     *
     * @return
     */
    public static Long getUserId() {
        try {
            String userIdInThreadLocal = ThreadContext.get(THREAD_LOCAL_VARIABLE_USER_ID);

            //如果已经写过用户的ID，则不用再次从缓存里面读取
            if (userIdInThreadLocal != null) {
                if (StringUtils.isEmpty(userIdInThreadLocal)) {
                    return null;
                } else {
                    return Long.valueOf(userIdInThreadLocal);
                }
            }

            HttpServletRequest request = getRequest();
            if (request == null) {
                logger.info("request is empty");
                return null;
            }

            String tokenHeader = request.getHeader(Constant.SESSION_TOKEN);

            if (StringUtils.isNotEmpty(tokenHeader)) {
                String userId = JRedisUtil.getKV(tokenHeader);

                logger.info("get the user id from token header {}", userId);

                if (StringUtils.isNotEmpty(userId)) {
                    return Long.valueOf(userId);
                }

                return null;
            }

            Long userId = getSessionAttribute(Constant.SESSION_USER_ID);
            logger.info("get the user from session {}", userId);
            return userId;
        } catch (Exception e) {
            logger.info("will clean the user env");
            //处理多环境的兼容性
            HttpServletRequest request = getRequest();

            if (request == null) {
                logger.info("request is empty");
                return null;
            }

            String tokenHeader = request.getHeader(Constant.SESSION_TOKEN);

            if (StringUtils.isNotEmpty(tokenHeader)) {
                JRedisUtil.delKV(tokenHeader);
            }

            //清除
            return null;
        }
    }

    /**
     * 添加用户ID
     *
     * @param user
     */
    public static void setUserId(User user) {
        ServletUtil.setSessionAttribute(Constant.SESSION_USER_ID, user.getId());
    }

    /**
     * 获取HTTP HEADER TOKEN
     *
     * @return
     */
    public static String getHeaderToken() {
        HttpServletRequest request = getRequest();
        return request.getHeader(Constant.SESSION_TOKEN);
    }

    /**
     * 获取session
     *
     * @return
     */
    public static HttpSession getSession() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        return request.getSession();
    }

    /**
     * 获取sessionId
     *
     * @return
     */
    public static String getSessionId() {
        return getSession().getId();
    }

    /**
     * 获取request
     *
     * @return
     */
    public static HttpServletRequest getRequest() {
        if (RequestContextHolder.getRequestAttributes() == null) {
            return null;
        }

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        return request;
    }

    /**
     * 获取response
     *
     * @return
     */
    public static HttpServletResponse getResponse() {
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        return response;
    }

    /**
     * 获取会话里的属性
     *
     * @param key
     * @param <T>
     * @return
     */
    public static <T> T getSessionAttribute(String key) {
        return (T) getSession().getAttribute(key);
    }

    /**
     * 设置会话的属性
     *
     * @param key
     * @param value
     */
    public static void setSessionAttribute(String key, Object value) {
        getSession().setAttribute(key, value);
    }

    /**
     * 清空会话的属性
     *
     * @param key
     */
    public static void cleanSessionAttribute(String key) {
        getSession().removeAttribute(key);
    }

    /**
     * 获取requestId
     *
     * @return
     */
    public static String getRequestId() {
        return ThreadContext.get(Constant.REQUEST_ID);
    }

    /**
     * 是否是C端的請求
     *
     * 前端请求的大小写不影响
     *
     * @return
     */
    public static boolean isCustomerRequest() {
        HttpServletRequest request = getRequest();
        String header = request.getHeader(Constant.CUSTOMER_REQUEST);
        return "true".equalsIgnoreCase(header);
    }

    public static String getAllHeaders() {
        HttpServletRequest request = getRequest();
        Enumeration<String> headerNames = request.getHeaderNames();
        HashMap<String, String> headerMap = new HashMap<>();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            headerMap.put(headerName, request.getHeader(headerName));
        }

        return JSON.toJSON(headerMap).toString();
    }

    /**
     * 返回文件给客户端
     *
     * @param file
     */
    public static void downloadFile(File file) throws IOException {
        HttpServletResponse response = getResponse();
        response.setHeader("content-type", "application/octet-stream");
        response.setContentType("application/octet-stream");

        response.setHeader("Content-Disposition", "attachment;filename=" + new String(file.getName().getBytes("UTF-8"), "ISO-8859-1"));
        response.setCharacterEncoding("UTF-8");
        IOUtils.copy(new FileInputStream(file), response.getOutputStream());
        IOUtils.closeQuietly(response.getOutputStream());
    }


    /**
     * 获取远端IP
     *
     * @param request
     * @return
     */
    public static String getRemoteIp(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");

        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "X-Real-IP".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }

        return ip;
    }

    /**
     * 请求体转化成字符串
     *
     * @return
     */
    public static String requestParamToString(HttpServletRequest request) {
        Map<String, String[]> map = request.getParameterMap();
        Set<Map.Entry<String, String[]>> entrySet = map.entrySet();

        List<RequestParam> requestParamList = entrySet.stream().map(entry -> {
            RequestParam requestParam = new RequestParam();
            requestParam.setKey(entry.getKey());
            requestParam.setValue(entry.getValue());
            return requestParam;
        }).collect(Collectors.toList());

        return JSONArray.toJSONString(requestParamList);
    }

    /**
     * 判断是否是B端支付的订单
     */
    public static boolean isBEndPayOrder() {
        Long userId = ServletUtil.getUserId();
        if (userId != null) {
            return true;
        }

        String terminalPay = ThreadContext.get(THREAD_LOCAL_VARIABLE_STRIPE_TERMINAL_PAY);
        return terminalPay != null;
    }

    public static boolean isAdminUser() throws Exception {
        Long userId = ServletUtil.getUserId();
        if (userId == null) {
            return false;
        }

        User user = getUser();
        if (user == null) {
            return false;
        }

        return user.getAdmin() != null && user.getAdmin();
    }
}
